/*
=======================================================================

  BOTS General class abilities

=======================================================================
*/

#include "g_local.h"
#include "bots_local.h"
#include "bots_ref.h"
#include "bots_bodyguard.h"
#include "bots_sniper.h"
#include "bots_soldier.h"
#include "bots_kamikazee.h"

static qboolean bFrozenMode = qfalse; 

// BEGIN bots - tbp
qboolean BOTS_shouldShuntCommands() {
	return bFrozenMode;
}

qboolean BOTS_toggleFrozenMode(gentity_t *ent) {
	char *name = ent->client?ent->client->pers.netname:"unknown";


	bFrozenMode = !bFrozenMode;
	if (bFrozenMode)
		trap_SendServerCommand( -1 , va("cp \"^7referee %s^7 said ^1FREEZE!^7\n\"",name) );
	else
		trap_SendServerCommand( -1 , va("cp \"^7referee %s^7 said ^1GO!^7\n\"",name) );

	BOTS_logRefereeCommands(ent,qtrue,"ref_freeze",
		bFrozenMode?"FROZEN":"UNFROZEN");
	return bFrozenMode;
}

// A function called from bg_pmove.c: Pmove()
// that tells if a player should be frozen for one reason or another (server side)
qboolean BOTS_shouldFreeze(int selfNum) {
	gentity_t	*self	= &g_entities[selfNum];

	if (!self->client)
		return qfalse;

	if (bFrozenMode && self->client && self->client->sess.sessionTeam != TEAM_SPECTATOR)
		return qtrue;

	// Now it will be easy to add a general freeze command for referees ;)
	switch (self->bots_class) {
	case BOTS_KAMIKAZEE:
		// Rewiring...
		if (self->client->i_rewireTime > level.time)
			return qtrue;
		break;
	case BOTS_BODYGUARD:
		// Laser setup...
		if (self->client->iLaserSetupFreezeTime > level.time)
			return qtrue;
		break;
	}

	return qfalse; // makes the compiler happy
}
// END bots - tbp




/////////////////////////////////////////////
//
// BOTS_weaponToggle
//
// This function toggles special firing modes.
//
void BOTS_weaponToggle(int clientNum, int classtype)
{
	gentity_t*	ent = g_entities + clientNum;

	if (!ent->client)
		return;

	if (ent->bots_class != classtype)
		return;

	if (ent->client->weapontoggle)
		ent->client->weapontoggle = qfalse;
	else
		ent->client->weapontoggle = qtrue;

	// splitmode rockets
	if (ent->bots_class == BOTS_SOLDIER)
	{
		if (ent->client->pers.classlevel < 2)
			ent->client->weapontoggle = qfalse;
		else
		{
			/*
			if (ent->client->weapontoggle)
				BOTS_cp_console( clientNum, "Split rockets activated.");
			else
				BOTS_cp_console( clientNum, "Normal rockets activated.");
			*/

			// turn tag cannon off
			ent->client->qb_tagMode		= qfalse;
			ent->tagEnt					= NULL;

			// make sure guided rockets are off
			ent->client->qb_guide = qfalse;
		}
	}// end splitmode rockets

	// captain split bfg
	else if (ent->bots_class == BOTS_CAPTAIN)
	{
		if (ent->client->pers.classlevel < 4)
			ent->client->weapontoggle = qfalse;
		else
		{
			/*
			if (ent->client->weapontoggle)
				BOTS_cp_console( clientNum, "Split BFG activated.");
			else
				BOTS_cp_console( clientNum, "Normal BFG activated.");
			*/
		}
	}// end splitmode bfg
}

/////////////////////////////////////////////
//
// BOTS_myclass
//
// This function will execute a config file based on which class the
// client is.
//
void BOTS_myclass(int clientNum)
{
	gentity_t* ent = g_entities + clientNum;
	char class_name[30];
	int i;

	switch(ent->bots_class)
	{
	case BOTS_CAPTAIN:
		strcpy(class_name, CLASS1);
		break;
	case BOTS_BODYGUARD:
		strcpy(class_name, CLASS2);
		break;
	case BOTS_SNIPER:
		strcpy(class_name, CLASS3);
		break;
	case BOTS_SOLDIER:
		strcpy(class_name, CLASS4);
		break;
	case BOTS_BERZERKER:
		strcpy(class_name, CLASS5);
		break;
	case BOTS_INFILTRATOR:
		strcpy(class_name, CLASS6);
		break;
	case BOTS_KAMIKAZEE:
		strcpy(class_name, CLASS7);
		break;
	case BOTS_NURSE:
		strcpy(class_name, CLASS8);
		break;
	case BOTS_SCIENTIST:
		strcpy(class_name, CLASS9);
		break;
	}

	for (i = 0; i < strlen(class_name); i++)
		class_name[i] = tolower(class_name[i]);

	trap_SendServerCommand( clientNum, va("server_myclass %s\n", class_name));
}

void BOTS_tracker(int clientNum)
{
	gentity_t* ent = g_entities + clientNum;

	gentity_t*	player;
	gentity_t*	list[MAX_CLIENTS];  // overkill, but I heard malloc doesn't work
	char*		tracker_string;
	int			i, j;
	char		classSpace[20];
	char		healthSpace[20];
	char*		tmpString;


	if (!ent->client)
		return;

	// check classtype
	if (ent->bots_class != BOTS_CAPTAIN && 
		ent->bots_class != BOTS_SNIPER  && 
		ent->bots_class != BOTS_SCIENTIST)
	{
		BOTS_cp_console( clientNum, "Only the Captain, Scientist, and Sniper can use the tracker.");
		return;
	}

	// check ammo
	if (ent->client->ps.ammo[WP_BFG] <= 0)
	{
		BOTS_cp_console( clientNum, "You don't have enough cells.");
		return;
	}

	// cell usage
	ent->client->ps.ammo[WP_BFG]--;

	// make sure each element is nulled out
	for (j = 0; j < MAX_CLIENTS; j++)
		list[j] = NULL;

	j = 0;
	for(i = 0; i < level.maxclients; i++)
	{
		vec3_t	playervec;
		qboolean alreadySet = qfalse;
		player = g_entities + i;

		if (!player->inuse || !player->client || (player == ent))
			continue; 
		if (player->client->sess.sessionTeam == TEAM_SPECTATOR)
			continue;
		if (OnSameTeam (ent, player))
			continue;

		VectorSubtract(ent->s.pos.trBase, player->s.pos.trBase, playervec);

		// out of range
		if (VectorLength(playervec) > 2000)
			continue;

		if (j == 0)
		{
			list[j] = player;
			j++;
		}
		else
		{
			vec3_t	listvec;
			int k;

			for (k = 0; k < j; k++)
			{
				float currentLength;
				float listLength;

				VectorSubtract(ent->s.pos.trBase, list[k]->s.pos.trBase, listvec);
				
				currentLength = VectorLength(playervec);
				listLength = VectorLength(listvec);
				if (currentLength < listLength)
				{
					int h = j;
					for (; h >= k; h--)
						list[h] = list[h-1];
					list[k] = player;
					j++;
					k = j;
					alreadySet = qtrue;
				}
			}
			
			if (!alreadySet)
			{
				list[j] = player;
				j++;
			}
		}
	}// for i < level.maxclients

	tracker_string =   va("Name  Class        Health  Range\n");
	tracker_string = va("%s-----  -----        ------  -----\n", tracker_string);

	for (i = 0; list[i] != NULL; i++)
	{
		vec3_t	listvec;
		char class_name[30];
		char netname[30];
		float length;

		VectorSubtract(ent->s.pos.trBase, list[i]->s.pos.trBase, listvec);
		length = VectorLength(listvec);

		switch(list[i]->bots_class)
		{
		case BOTS_CAPTAIN:
			strcpy(class_name, CLASS1);
			break;
		case BOTS_BODYGUARD:
			strcpy(class_name, CLASS2);
			break;
		case BOTS_SNIPER:
			strcpy(class_name, CLASS3);
			break;
		case BOTS_SOLDIER:
			strcpy(class_name, CLASS4);
			break;
		case BOTS_BERZERKER:
			strcpy(class_name, CLASS5);
			break;
		case BOTS_INFILTRATOR:
			strcpy(class_name, CLASS6);
			break;
		case BOTS_KAMIKAZEE:
			strcpy(class_name, CLASS7);
			break;
		case BOTS_NURSE:
			strcpy(class_name, CLASS8);
			break;
		case BOTS_SCIENTIST:
			strcpy(class_name, CLASS9);
			break;
		default:
			strcpy(class_name, "ERROR");
			break;
		}

		// remove the stupid ass colors losers use
		strcpy(netname, list[i]->client->pers.netname);
		Q_CleanStr(netname);
		netname[15] = 0;

		for(j = 0; j < 11 - strlen(class_name) + 2; j++)
			classSpace[j] = ' ';
		classSpace[j] = 0;

		tmpString = va("%d", list[i]->health);
		for (j = 0; j < 6 - strlen(tmpString) + 2; j++)
			healthSpace[j] = ' ';
		healthSpace[j] = 0;


		tracker_string = va("%s%s  %s%s%d%s%d\n", tracker_string, 
													netname,
													class_name, classSpace, 
													list[i]->health, healthSpace,
													(int)length);
	}// for list != NULL

	trap_SendServerCommand( clientNum, va("bots_table \"%s\n\"", tracker_string));
	//BOTS_cp_console(clientNum, tracker_string);
}

// only works with lightmap - not with vertex
void BOTS_flashlight(int clientNum)
{
	gentity_t* ent = g_entities + clientNum;

	gentity_t*	light;

	if (!ent->client)
		return;

	// flashlight is on - free the entity and return
	if (ent->flashlight)
	{
		G_FreeEntity(ent->flashlight);
		ent->flashlight = NULL;
		return;
	}

	//
	// create a temporary entity for this flare
	//
	light					= G_Spawn();
	light->s.eType			= ET_BOTS_FLARE;
	light->s.modelindex		= 1;
	light->s.modelindex2	= 0; // This is non-zero if it's a dropped item
	light->s.number			= light - g_entities;
	light->s.frame			= 1;
	light->classname		= "flashlight";
	light->parent			= ent;
	light->think			= BOTS_sight_think;
	light->nextthink		= level.time + FRAMETIME;
	light->s.clientNum		= clientNum;

	trap_LinkEntity (light);

	ent->flashlight = light;
}

void BOTS_sendalarm(int clientNum)
{
	gentity_t*  ent = g_entities + clientNum;
	int			i;

	if (!ent->client)
		return;

	// check classtype
	if (ent->bots_class != BOTS_CAPTAIN && 
		ent->bots_class != BOTS_SNIPER)
	{
		BOTS_cp_console( clientNum, "Only the Captain and Sniper can send alarms.");
		return;
	}

	for (i = 0; i < level.maxclients; i++)
	{
		gentity_t*  player = g_entities + i;

		if (!player->client)
			continue;
		if (!player->client->pers.alarmmsg)
			continue;
		if (!OnSameTeam (ent, player))
			continue;

		// this next part will format the alarm message so that we can
		// send it to our bots_table function
		//
		//tbp: my ass
#if 0
		if (player) // don't need this, but you can't declare on the fly with C
		{
			char  alarmnameString[100];
			char  messageString[100];
			char  playerString[100];

			int len, spaces = 22;

			int i, j;

			len = strlen(ent->alarmmsg);

			// set up format spacing
			for (i = 0; i < spaces; i++)
			{
				alarmnameString[i] = ' ';
				messageString[i]  = ' ';
				playerString[i]    = ' ';
			}

			// get alarm name
			for (i = 0, j = 0; i < len; i++, j++)
			{
				if (ent->alarmmsg[i] != '\n')
					alarmnameString[spaces + j] = ent->alarmmsg[i];
				else
					break;
			}
			alarmnameString[spaces + j] = '\0';
			i++;

			// get alarm message
			//for (i, j = 0; i < len; i++, j++)
			for (j = 0; i < len; i++, j++)
			{
				if (ent->alarmmsg[i] != '\n')
					messageString[spaces + j] = ent->alarmmsg[i];
				else
					break;
			}
			messageString[spaces + j] = '\0';
			i++;

			// get client
			// for (i, j = 0; i < len; i++, j++)
			for (j = 0; i < len; i++, j++)
			{
				if (ent->alarmmsg[i] != '\n')
					playerString[spaces + j] = ent->alarmmsg[i];
				else
					break;
			}
			playerString[spaces + j] = '\0';

			trap_SendServerCommand( player->s.clientNum, va("bots_table \"%s\n%s\n%s\n\"", 
				                    alarmnameString,
									messageString,
									playerString));
		}		
#endif
		if (strlen(ent->alarmmsg) > 0)
			trap_SendServerCommand( player->s.clientNum, va("bots_table \"%s\"",ent->alarmmsg) );
	}
}

/////////////////////////////////////////////
//
// BOTS_dropflag
//
// Drops the flag if the client has one.
//
void BOTS_dropflag(int clientNum)
{
	gentity_t*  ent = g_entities + clientNum;
	gentity_t*	drop;
	gitem_t*	item;
	int			flag;
	vec3_t		angles, velocity, origin, forward;

	// check to see if the client has the flag
	if (!ent->client->keyindex	|| 
		(ent->client->ps.powerups[PW_REDFLAG]  < level.time	&&
		 ent->client->ps.powerups[PW_BLUEFLAG] < level.time))
	{
		BOTS_cp_console(clientNum, "You do not have the flag\n");
		return;
	}

	if (ent->client->ps.powerups[PW_REDFLAG] > level.time)
		flag = PW_REDFLAG;
	else
		flag = PW_BLUEFLAG;

	item = BG_FindItemForPowerup(flag);

	// set aiming directions
	VectorCopy( ent->s.apos.trBase, angles );

	// set the origin of the launch away from the client
	AngleVectors (ent->client->ps.viewangles, forward, NULL, NULL);
	forward[2] = 0;
	VectorMA(ent->s.pos.trBase, 100, forward, origin);

	angles[PITCH] = 0;	// always forward

	AngleVectors( angles, velocity, NULL, NULL );
	VectorScale( velocity, 150, velocity );
	velocity[2] += 100;

	drop = LaunchItem( item, origin, velocity );

	// remove the flag from the client
	ent->client->ps.powerups[flag] = 0;
	ent->client->keyindex = 0;
}

void BOTS_playerid(int clientNum)
{
	gentity_t*  ent = g_entities + clientNum;
	vec3_t		forward;
	vec3_t		muzzle, wallp;
	char		class_name[30];
	char		netname[30];
	trace_t		tr;
	gentity_t	*traceEnt;

	if (!ent->client)
		return;

	// set aiming directions
	AngleVectors (ent->client->ps.viewangles, forward, NULL, NULL);

	// setup muzzle point
	CalcMuzzlePoint(ent, forward, NULL, NULL, muzzle);

	VectorNormalize (forward);

	// Setup end point of the vector we want to trace
	VectorCopy(muzzle, wallp);
	VectorMA(wallp, 8192, forward, wallp);

	// do the trace
	trap_Trace(&tr, muzzle, NULL, NULL, wallp, ent->s.number, MASK_SHOT);

	// Line complete ? (ie. no collision)
	if (tr.fraction == 1.0)
		return;

	traceEnt = &g_entities[ tr.entityNum ];

	// make sure the entity returned is a client
	if (!traceEnt->client)
		return;

	switch (traceEnt->bots_class) 
	{
	case BOTS_CAPTAIN:
		strcpy(class_name, CLASS1);
		break;
	case BOTS_BODYGUARD:
		strcpy(class_name, CLASS2);
		break;
	case BOTS_SNIPER:
		strcpy(class_name, CLASS3);
		break;
	case BOTS_SOLDIER:
		strcpy(class_name, CLASS4);
		break;
	case BOTS_BERZERKER:
		strcpy(class_name, CLASS5);
		break;
	case BOTS_INFILTRATOR:
		strcpy(class_name, CLASS6);
		break;
	case BOTS_KAMIKAZEE:
		strcpy(class_name, CLASS7);
		break;
	case BOTS_NURSE:
		strcpy(class_name, CLASS8);
		break;
	case BOTS_SCIENTIST:
		strcpy(class_name, CLASS9);
		break;
	default:
		strcpy(class_name, "ERROR");
		break;
	}

	// remove the stupid ass colors losers use
	strcpy(netname, traceEnt->client->pers.netname);
	Q_CleanStr(netname);

	BOTS_cp_console(clientNum, va("Name = %s\nClass = %s",
								   netname, class_name));
}

void BOTS_locatepromo(int clientNum)
{
	gentity_t*  ent = g_entities + clientNum;
	gentity_t*  captain = NULL;
	char		netname[30];
	vec3_t		dist1;

	if (!ent->client)
		return;

	if (ent->bots_team == TEAM_RED)
		captain = bots_getCaptain(TEAM_RED);
	else
		captain = bots_getCaptain(TEAM_BLUE);

	if (!captain)
	{
		BOTS_cp_console(clientNum, "You don't have a Captain");
		return;
	}

	if (!ent->promotionkey)
	{
		// remove the stupid ass colors losers use
		strcpy(netname, captain->client->pers.netname);
		Q_CleanStr(netname);

		//BOTS_cp_console(clientNum, va("Captain %s has the promotion key", netname));
		trap_SendServerCommand( clientNum, va("bots_table \"Captain %s has the promotion key\n\"", netname) );
		return;
	}

	VectorSubtract(ent->s.pos.trBase, ent->promotionkey->s.pos.trBase, dist1);
	trap_SendServerCommand( clientNum, va("bots_table \"%sDistance to key->%i\n\"", 
											  "                       ", (int)VectorLength(dist1)));
}


void BOTS_locatetech(int clientNum)
{
	gentity_t*  ent = g_entities + clientNum;
	gentity_t*  scientist = NULL;
	char		netname[30];
	vec3_t		dist1;

	if (!ent->client)
		return;

	if (ent->bots_team == TEAM_RED)
		scientist = bots_getScientist(TEAM_RED);
	else
		scientist = bots_getScientist(TEAM_BLUE);

	if (!scientist)
	{
		BOTS_cp_console(clientNum, "You don't have a Scientist");
		return;
	}

	if (!ent->techkey)
	{
		// remove the stupid ass colors losers use
		strcpy(netname, scientist->client->pers.netname);
		Q_CleanStr(netname);

		//BOTS_cp_console(clientNum, va("Scientist %s has the tech key", netname));
		trap_SendServerCommand( clientNum, va("bots_table \"Scientist %s has the tech key\n\"", netname));
		return;
	}

	VectorSubtract(ent->s.pos.trBase, ent->techkey->s.pos.trBase, dist1);
	trap_SendServerCommand( clientNum, va("bots_table \"Distance to key->%i\n\"", (int)VectorLength(dist1)));
}

void BOTS_impeach(int clientNum)
{
	gentity_t*  ent = g_entities + clientNum;
	int impeachVotes = 0;
	int teamMembers = 0;
	int i;

	if (!ent->client)
		return;

	if (!bots_getCaptain(ent->bots_team))
	{
		BOTS_cp_console(clientNum, "You don't have a Captain");
		return;
	}

	//BOTS_set_impeach(ent);

	// record the vote
	if (!ent->client->pers.impeachvote)
		ent->client->pers.impeachvote = qtrue;

	for(i = 0; i < level.maxclients; i++)
	{
		gentity_t* player = g_entities + i;

		if (!player->client)
			continue;
		if (!OnSameTeam(ent, player))
			continue;

		teamMembers++;
		if (player->client->pers.impeachvote)
			impeachVotes++;
	}

	// Captain doesn't count
	teamMembers--;

	if (teamMembers == 0)
		return;

	if (ent->client->sess.sessionTeam == TEAM_RED)
		G_Printf(S_COLOR_YELLOW "%i people have voted to impeach the male captain.\n", impeachVotes);
	else
		G_Printf(S_COLOR_YELLOW "%i people have voted to impeach the female captain.\n", impeachVotes);

	if(impeachVotes / teamMembers > .75)
	{
//		char	   netname[30];
		gentity_t* captain = bots_getCaptain(ent->bots_team);

		// remove the stupid ass colors losers use
		//strcpy(netname, captain->client->pers.netname);
		//Q_CleanStr(netname);
		BOTS_cp_console(-1, va("%s has been impeached.", captain->client->pers.netname));
		captain->client->pers.impeached = qtrue;
		bots_ChangeClass (captain, BOTS_BODYGUARD);
	}
}

void BOTS_poison_player(gentity_t* ent, qboolean fromWeapon)
{
	const int	iMAX_POISON_TIME = 15000;
	int			delta;


	if (!ent->client)
		return;

	if (ent->bots_class == BOTS_NURSE)
		return;

	if (fromWeapon)
		delta = BOTS_POISON_TIME_WEAPON;
	else
		delta = BOTS_POISON_TIME_HEALTH;

	//tbp: now it's a powerup
	if (ent->client->ps.powerups[PW_POISON] != 0)
		ent->client->ps.powerups[PW_POISON] += delta; // Cumulative
	else
		ent->client->ps.powerups[PW_POISON] = level.time + delta;

	// There's a max
	if ((ent->client->ps.powerups[PW_POISON] - level.time) > iMAX_POISON_TIME)
		ent->client->ps.powerups[PW_POISON] = level.time + iMAX_POISON_TIME;

	ent->client->ps.damagePitch = ent->client->ps.viewangles[PITCH]/360.0 * 256;
	ent->client->ps.damageYaw = ent->client->ps.viewangles[YAW]/360.0 * 256;
}

void BOTS_grenade(int clientNum)
{
	gentity_t*  ent = g_entities + clientNum;
	int			tmp;
	char	string_velocity[20];

	if (!ent->client)
		return;

	if (ent->client->i_grenTossTime > level.time)
		return;

	if (ent->client->ps.ammo[WP_GRENADE_LAUNCHER] <= 0)
		return;

	if (trap_Argc() <= 1)
		return;
	
	trap_Argv(1, string_velocity, sizeof(string_velocity));
	ent->client->i_hand_gren_vel = atoi(string_velocity);

	if (ent->client->i_hand_gren_vel == 0)
	{
		ent->client->i_hand_gren_vel = 200;
	}
	else
	{
		ent->client->i_hand_gren_vel += 500;
		ent->client->i_hand_gren_vel /= 1000;

		if (ent->bots_team == TEAM_RED)
		{
			if (ent->client->i_hand_gren_vel  == 1)
				ent->client->i_hand_gren_vel = 600;
			else if (ent->client->i_hand_gren_vel == 2)
				ent->client->i_hand_gren_vel = 900;
			else
				ent->client->i_hand_gren_vel = 1200;
		}
		else
		{
			if (ent->client->i_hand_gren_vel  == 1)
				ent->client->i_hand_gren_vel = 300;
			else if (ent->client->i_hand_gren_vel == 2)
				ent->client->i_hand_gren_vel = 600;
			else
				ent->client->i_hand_gren_vel = 800;
		}
	}

	ent->client->ps.ammo[WP_GRENADE_LAUNCHER]--;
	ent->client->i_grenTossTime = level.time + 1000;

	tmp = ent->s.weapon;
	
	ent->client->qb_grenMode = qtrue;
	ent->s.weapon = WP_GRENADE_LAUNCHER;
	FireWeapon(ent);
	ent->s.weapon = tmp;
	ent->client->qb_grenMode = qfalse;
	ent->client->ps.weaponTime = 1000;
	ent->client->ps.weaponstate = WEAPON_DROPPING;

	// make him look like he threw something...
	ent->client->ps.torsoAnim = ((ent->client->ps.torsoAnim & ANIM_TOGGLEBIT) ^ ANIM_TOGGLEBIT)| TORSO_ATTACK2;
}

void BOTS_proxy_think(gentity_t* self)
{
	gentity_t* player = NULL;

	if (level.time > self->i_proxTime || !self->parent)
	{
		G_ExplodeMissile(self);
		return;
	}
	
	self->think = BOTS_proxy_think;

	while ((player = findradiusCLIENT(player, self->s.pos.trBase, 100)) != NULL)
	{
		if (!player->client)
			continue;
		if (OnSameTeam(player, self->parent))
			continue;
		if (player->health <= 0)
			continue;
		if (!visible(player, self))
			continue;

		if (player->bots_class == BOTS_KAMIKAZEE && player->client->qb_autorewireMode)
		{
			int i;

			switch (player->client->pers.classlevel) {
			default:
			case 0:
			case 1:
				player->client->i_rewireTime = level.time + 3000;
				break;
			case 2:
				player->client->i_rewireTime = level.time + 2000;
				break;
			case 3:
				player->client->i_rewireTime = level.time + 1000;
				break;
			case 4:
				player->client->i_rewireTime = 0;
			}

			self->parent->client->i_numProx--;
			self->parent = player;

			for(i = 0; i < level.maxclients; i++)
			{
				gentity_t* teamMate = g_entities + i;

				if (!teamMate->client)
					continue;
				if (!teamMate->inuse)
					continue;
				if (!OnSameTeam (player, teamMate))
					continue;
				
				if (player != teamMate)
					BOTS_console(teamMate->s.clientNum, va("%s is rewiring a grenade.", 
									player->client->pers.netname));
				else
					BOTS_cp_console(player->s.clientNum, "You are rewiring a grenade.");
			}

			break;
		}
		else
		{
			self->think = G_ExplodeMissile;
			break;
		}
	}

	self->nextthink = level.time + FRAMETIME;
}

void BOTS_blind_explode(gentity_t* self)
{
	gentity_t*	player = NULL;
	float		fBlindRadius = 300.0f; // 200 * level * level, geez

	if (!self->parent)
		return;

	if (self->parent->client->pers.classlevel > 1)
		fBlindRadius *= (float) self->parent->client->pers.classlevel;

	while ((player = findradiusCLIENT(player, self->s.pos.trBase, fBlindRadius)) != NULL)
	{
		if (!player->client)
			continue;
		if (player->client->sess.sessionTeam == TEAM_SPECTATOR)
			continue;
		if (player->client->qb_blink)
			continue;
		// raged zerks and respawning players will not be blinded.
		if (player->client->ps.powerups[PW_FLIGHT] > level.time)
			continue;
		if (OnSameTeam(player, self->parent))
			continue;
		if (!visible(self, player))
			continue;

		player->client->ps.powerups[PW_BLIND] = level.time + BOTS_BLIND_TIME;

		// send message to person that was blinded
		BOTS_cp_console(player->s.clientNum, va("You have been blinded by %s.", self->parent->client->pers.netname));

		// send message to the nurse that threw the grenade
		BOTS_console(self->parent->s.clientNum, va("You have blinded %s.", player->client->pers.netname));
	}

	self->think = G_ExplodeMissile;
	self->nextthink = level.time + FRAMETIME;
	trap_LinkEntity( self );
}

void BOTS_grentog(int clientNum)
{
	gentity_t*  ent = g_entities + clientNum;

	if (!ent->client)
		return;

	// proxies
	if (ent->bots_class == BOTS_BODYGUARD || ent->bots_class == BOTS_CAPTAIN)
	{
		ent->client->qb_proxMode = !ent->client->qb_proxMode;
		/*
		if (ent->client->qb_proxMode)
			BOTS_cp_console(clientNum, "Proximity grenades activated.");
		else
			BOTS_cp_console(clientNum, "Proximity grenades deactivated.");
		*/
		return;
	}

	// decoy grenades
	else if (ent->bots_class == BOTS_INFILTRATOR)
	{
		ent->client->qb_decoyGrenMode = !ent->client->qb_decoyGrenMode;
		/*
		if (ent->client->qb_decoyGrenMode)
			BOTS_cp_console(clientNum, "Decoy grenades activated.");
		else
			BOTS_cp_console(clientNum, "Decoy grenades deactivated.");
		*/
		return;
	}

	// flash
	else if (ent->bots_class == BOTS_NURSE)
	{
		ent->client->qb_flashMode = !ent->client->qb_flashMode;
		/*
		if (ent->client->qb_flashMode)
			BOTS_cp_console(clientNum, "Flash grenades activated.");
		else
			BOTS_cp_console(clientNum, "Flash grenades deactivated.");
		*/
		return;
	}

	// teleport grenades
	else if (ent->bots_class == BOTS_SCIENTIST)
	{
		if (ent->client->pers.classlevel < 1)
		{
			BOTS_cp_console(clientNum, "You must be at least level 1 to use temporal distortion grenades.");
			return;
		}

		ent->client->qb_teleportMode = !ent->client->qb_teleportMode;
		/*
		if (!ent->client->qb_teleportMode)
			BOTS_cp_console(clientNum, "Temporal distortion grenades deactivated.");
		else
			BOTS_cp_console(clientNum, "Temporal distortion grenades activated.");
		*/
		return;
	}
}

void BOTS_explode_nearby_grenades(gentity_t* self)
{
	gentity_t* grenade = NULL;

	if (Q_stricmp (self->classname, "hook")   == 0 ||
		Q_stricmp (self->classname, "bfg")    == 0 ||
		Q_stricmp (self->classname, "plasma") == 0)
		return;

	// find proxies and decoys and destroy them
	while ((grenade = findradius(grenade, self->s.pos.trBase, 80)) != NULL)
	{
		if (grenade == self)
			continue;
		if (!grenade->classname)
			continue;
		if (Q_stricmp (grenade->classname, "proxy_grenade") != 0 &&
			Q_stricmp (grenade->classname, "decoy_grenade") != 0)
			continue;

		grenade->think = G_ExplodeMissile;
		grenade->nextthink = level.time + 400;
	}
}

qboolean BOTS_Pickup_Powerup(gentity_t* ent, int powerup)
{
	if (!ent->client)
		return qfalse;

	if (ent->client->i_powerup == PW_NONE)
	{
		ent->client->i_powerup = powerup;
		return qtrue;
	}

	return qfalse;	
}

void BOTS_powerup(int clientNum)
{
	int duration = 15000;
	gentity_t*  ent = g_entities + clientNum;

	if (!ent->client)
		return;
	if (ent->client->i_powerup == PW_NONE)
		return;

	ent->client->ps.powerups[ent->client->i_powerup] = level.time + duration;
	ent->client->i_powerup = PW_NONE;
}

void BOTS_blink(int clientNum, qboolean qb_eyesClosed)
{
	gentity_t*  ent = g_entities + clientNum;

	if (!ent->client)
		return;

	ent->client->qb_blink = qb_eyesClosed;
}

void BOTS_drop_item(int clientNum, char* cmd)
{
	gentity_t*  ent		= g_entities + clientNum;
	gentity_t*	drop;
	gitem_t*	item	= NULL;
	vec3_t		angles, velocity, origin, forward;

	int			amount	= 0;
	
	char arg[20];
	trap_Argv(1, arg, sizeof(arg));

	if (Q_stricmp (arg, "bullets") == 0)
	{
		item = BG_FindItem("Bullets");
		amount = ent->client->ps.ammo[WP_MACHINEGUN];
		ent->client->ps.ammo[WP_MACHINEGUN] = 0;	
	}
	else if (Q_stricmp (arg, "cells") == 0)
	{
		item = BG_FindItem("Cells");
		amount = ent->client->ps.ammo[WP_BFG];
		ent->client->ps.ammo[WP_BFG] = 0;	
	}
	else if (Q_stricmp (arg, "grenades") == 0)
	{
		item = BG_FindItem("Grenades");
		amount = ent->client->ps.ammo[WP_GRENADE_LAUNCHER];
		ent->client->ps.ammo[WP_GRENADE_LAUNCHER] = 0;	
	}
	else if (Q_stricmp (arg, "shells") == 0)
	{
		item = BG_FindItem("Shells");
		amount = ent->client->ps.ammo[WP_SHOTGUN];
		ent->client->ps.ammo[WP_SHOTGUN] = 0;	
	}
	else if (Q_stricmp (arg, "slugs") == 0)
	{
		item = BG_FindItem("Slugs");
		amount = ent->client->ps.ammo[WP_RAILGUN];
		ent->client->ps.ammo[WP_RAILGUN] = 0;	
	}
	else if (Q_stricmp (arg, "rockets") == 0)
	{
		item = BG_FindItem("Rockets");
		amount = ent->client->ps.ammo[WP_ROCKET_LAUNCHER];
		ent->client->ps.ammo[WP_ROCKET_LAUNCHER] = 0;	
	}

	// if amount is not greater than zero, check to see if it is armor.
	if (amount <= 0)
	{
		if (Q_stricmp (arg, "armor") == 0)
		{
			item = BG_FindItem("Armor");
			amount = ent->client->ps.stats[STAT_ARMOR];
			ent->client->ps.stats[STAT_ARMOR] = 0;
		}
		else
			item = NULL;

		if (amount <= 0)
			item = NULL;
	}

	// only toss an item if we have one.
	if (item)
	{
		// set aiming directions
		VectorCopy( ent->s.apos.trBase, angles );

		// set the origin of the launch away from the client
		AngleVectors (ent->client->ps.viewangles, forward, NULL, NULL);
		forward[2] = 0;
		VectorMA(ent->s.pos.trBase, 100, forward, origin);

		angles[PITCH] = 0;	// always forward

		AngleVectors( angles, velocity, NULL, NULL );
		VectorScale( velocity, 150, velocity );
		velocity[2] += 200 + crandom() * 50;

		drop = LaunchItem( item, origin, velocity );
		drop->item->quantity = amount;
	}
}

/////////////////////////////////////////////
//
// BOTS_ClassGeneralCommands
//
// This function contains general commands used by many classes
//
qboolean BOTS_ClassGeneralCommands(int clientNum, char* cmd)
{
	if (Q_stricmp (cmd, "myclass") == 0 )
	{
		BOTS_myclass(clientNum);
		return qtrue;
	}
	else if (Q_stricmp (cmd, "tracker") == 0 )
	{
		BOTS_tracker(clientNum);
		return qtrue;
	}
	else if (Q_stricmp (cmd, "flashlight") == 0 )
	{
		BOTS_flashlight(clientNum);
		return qtrue;
	}
	else if (Q_stricmp (cmd, "sendalarm") == 0 )
	{
		BOTS_sendalarm(clientNum);
		return qtrue;
	}
	else if (Q_stricmp (cmd, "dropflag") == 0 )
	{
		BOTS_dropflag(clientNum);		
		return qtrue;
	}
	else if (Q_stricmp (cmd, "locatepromo") == 0 )
	{
		BOTS_locatepromo(clientNum);		
		return qtrue;
	}
	else if (Q_stricmp (cmd, "locatetech") == 0 )
	{
		BOTS_locatetech(clientNum);		
		return qtrue;
	}
	else if (Q_stricmp (cmd, "impeach") == 0 )
	{
		BOTS_impeach(clientNum);
		return qtrue;
	}
	else if (Q_strncmp (cmd, "cgame_to_server_gren", strlen ("cgame_to_server_gren")) == 0)
	{
		BOTS_grenade(clientNum);
		return qtrue;
	}
	else if (Q_stricmp (cmd, "grentog") == 0 )
	{
		BOTS_grentog(clientNum);
		return qtrue;
	}
	else if (Q_stricmp (cmd, "powerup") == 0 )
	{
		BOTS_powerup(clientNum);
		return qtrue;
	}
	else if (Q_stricmp (cmd, "plusblink") == 0 )
	{
		BOTS_blink(clientNum, qtrue);
		return qtrue;
	}
	else if (Q_stricmp (cmd, "minusblink") == 0 )
	{
		BOTS_blink(clientNum, qfalse);
		return qtrue;
	}
	else if (Q_stricmp (cmd, "drop") == 0 )
	{
		BOTS_drop_item(clientNum, cmd);
		return qtrue;
	}

//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
// START NITS DEBUG

	else if (Q_stricmp (cmd, "[level]") == 0 )
	{
		char arg[20];
		trap_Argv(1, arg, sizeof(arg));

		g_entities[clientNum].client->pers.classlevel = atoi(arg);
		Com_Printf("Your are Level %s\n", arg);
		return qtrue;
	}
	else if (Q_stricmp (cmd, "[promo]") == 0)
	{
		char arg[20];
		int* promotech = BOTS_get_promotech_points(g_entities[clientNum].client->sess.sessionTeam);

		trap_Argv(1, arg, sizeof(arg));
		promotech[0] = atoi(arg);
		promotech[1] = atoi(arg);
		BOTS_set_promotech_points(g_entities[clientNum].client->sess.sessionTeam, promotech);
		return qtrue;
	}
	else if (Q_stricmp (cmd, "poison1") == 0)
	{
		BOTS_poison_player(&g_entities[clientNum], qfalse);
		return qtrue;
	}
	else if (Q_stricmp (cmd, "poison_debug") == 0)
	{
		char arg[20];
		trap_Argv(1, arg, sizeof(arg));
		trap_SendServerCommand( clientNum, va("server_to_cgame_poison_debug %s\n", arg));
		return qtrue;
	}	
// END NITS DEBUG
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////

	return qfalse;
}
